home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / pop3serv.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  21KB  |  1,021 lines

  1. /* POP3 Server state machine - see RFC 1225
  2.  *
  3.  *      Jan 92  Erik Olson olson@phys.washington.edu
  4.  *              Taken from POP2 server code in NOS 910618
  5.  *              Rewritten/converted to POP3
  6.  *      Feb 92  William Allen Simpson
  7.  *              integrated with current work
  8.  *      Aug-Oct 92      Mike Bilow, N1BEE, mikebw@ids.net
  9.  *              Extensive bug fixes; changed uses of Borland stat()
  10.  *              to fsize() in order to fix intermittent crashes;
  11.  *              corrected confusion of sockmode()
  12.  *
  13.  *  "Need-to" list: XTND XMIT (to get WinQVTnet to work)
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <fcntl.h>
  18. #include <time.h>
  19. #include <sys/stat.h>
  20. #ifdef UNIX
  21. #include <sys/types.h>
  22. #endif
  23. #if     defined(__STDC__) || defined(__TURBOC__)
  24. #include <stdarg.h>
  25. #endif
  26. #include <ctype.h>
  27. #include <setjmp.h>
  28. #include "global.h"
  29. #include "mbuf.h"
  30. #include "cmdparse.h"
  31. #include "socket.h"
  32. #include "proc.h"
  33. #include "files.h"
  34. #include "smtp.h"
  35. #include "dirutil.h"
  36.  
  37. #ifdef POP3SERVER
  38.  
  39. /* ---------------- common server data structures ---------------- */
  40. /* POP message pointer element */
  41.  
  42. struct pop_msg {
  43.     long len;
  44.     long pos;
  45.     int deleted;
  46.     struct pop_msg *next;
  47. };
  48.  
  49. /* POP server control block */
  50.  
  51. struct pop_scb {
  52.     int socket;             /* socket number for this connection */
  53.     char state;             /* server state */
  54. #define      LSTN       0
  55. #define      AUTH       1
  56. #define      TRANS      2
  57. #define      UPDATE     3
  58. #define      DONE       5
  59.  
  60.     char    buf[TLINELEN];   /* input line buffer */
  61.     char    count;          /* line buffer length */
  62.     char    username[64];   /* user/folder name */
  63.     FILE    *wf;            /* work folder file pointer */
  64.     int     folder_len;     /* number of msgs in current folder */
  65.     int     high_num;       /* highest message number accessed */
  66.     long    folder_file_size; /* length of the current folder file, in bytes */
  67.     char    folder_modified; /* mail folder contents modified flag */
  68.     struct pop_msg *msg;    /* message database link-list */
  69. };
  70.  
  71. #define NULLSCB  (struct pop_scb *)0
  72.  
  73. /* Response messages -- '\n' is converted to '\r\n' by the socket code */
  74.  
  75. static char     count_rsp[]     = "+OK you have %d messages\n",
  76.         error_rsp[]     = "-ERR %s\n",
  77.         greeting_msg[]  = "+OK %s POP3 ready\n",
  78.         user_rsp[]      = "+OK user\n",
  79. #if 0
  80.         pass_rsp[]      = "+OK password\n",
  81. #endif
  82.         stat_rsp[]      = "+OK %d %ld\n",
  83.         list_single_rsp[]       = "+OK %d %d\n",
  84.         list_multi_rsp[]        = "+OK %d messages (%ld octets)\n",
  85.         retr_rsp[]      = "+OK %ld octets\n",
  86.         multi_end_rsp[] = ".\n",
  87.         dele_rsp[]      = "+OK message %d deleted\n",
  88.         noop_rsp[]      = "+OK\n",
  89.         last_rsp[]      = "+OK %d\n",
  90.         signoff_msg[]   = "+OK Bye, bye-bye, bye now, goodbye\n";
  91.  
  92. static void rrip __ARGS((char *s));
  93. static struct pop_scb *create_scb __ARGS((void));
  94. static void delete_scb __ARGS((struct pop_scb *scb));
  95. static void popserv __ARGS((int s,void *unused,void *p));
  96. static int poplogin __ARGS((char *pass,char *username));
  97.  
  98. static void pop_sm __ARGS((struct pop_scb *scb));
  99.  
  100. static int Spop = -1; /* prototype socket for service */
  101.  
  102.  
  103. /* Start up POP receiver service */
  104. int
  105. #ifdef PROTOTYPES
  106. pop3start(int argc,char **argv,void *p)
  107. #else
  108. pop3start(argc,argv,p)
  109.  
  110. int argc;
  111. char *argv[];
  112. void *p;
  113. #endif
  114.  
  115. {
  116.     struct sockaddr_in lsocket;
  117.     int s;
  118.  
  119.     if (Spop != -1) {
  120.         return 0;
  121.     }
  122.  
  123.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  124.     chname(Curproc,"POP3 listener");
  125.  
  126.     lsocket.sin_family = AF_INET;
  127.     lsocket.sin_addr.s_addr = INADDR_ANY;
  128.     if(argc < 2)
  129.         lsocket.sin_port = IPPORT_POP3;
  130.     else
  131.         lsocket.sin_port = atoi(argv[1]);
  132.  
  133.     Spop = socket(AF_INET,SOCK_STREAM,0);
  134.  
  135.     bind(Spop,(char *)&lsocket,sizeof(lsocket));
  136.  
  137.     listen(Spop,1);
  138.  
  139.     for (;;) {
  140.         if((s = accept(Spop,NULLCHAR,(int *)NULL)) == -1)
  141.             break;  /* Service is shutting down */
  142.  
  143.         /* Spawn a server */
  144.  
  145.         newproc("POP3 server",2048,popserv,s,NULL,NULL,0);
  146.     }
  147.     return 0;
  148. }
  149.  
  150. /* Shutdown POP3 service (existing connections are allowed to finish) */
  151.  
  152. int
  153. #ifdef PROTOTYPES
  154. pop3stop(int argc,char **argv,void *p)
  155. #else
  156. pop3stop(argc,argv,p)
  157. int argc;
  158. char *argv[];
  159. void *p;
  160. #endif
  161.  
  162. {
  163.     if(Spop != -1) {
  164.         close_s(Spop);
  165.         Spop = -1;
  166.     } else
  167.         tprintf("No POP3 listener to stop\n");
  168.     return 0;
  169. }
  170.  
  171. static void
  172. popserv(s,unused,p)
  173. int s;
  174. void *unused;
  175. void *p;
  176. {
  177.     struct pop_scb *scb;
  178.     char *cp;
  179.  
  180.     sockowner(s,Curproc);           /* We own it now */
  181.     log(s,"open POP3");
  182.  
  183.     if((scb = create_scb()) == NULLSCB) {
  184.         tprintf(Nospace);
  185.         log(s,"close POP3 - no space");
  186.         close_s(s);
  187.         return;
  188.     }
  189.  
  190.     scb->socket = s;
  191.     scb->state  = AUTH;
  192.  
  193.     sockmode(s,SOCK_ASCII);         /* N1BEE */
  194.     (void) usprintf(s,greeting_msg,Hostname);
  195.  
  196. loop:   if ((scb->count = recvline(s,scb->buf,TLINELEN)) == -1){
  197.         /* He closed on us */
  198.  
  199.         goto quit;
  200.     }
  201.  
  202.     rip(scb->buf);
  203.     if (strlen(scb->buf) == 0)      /* Ignore blank cmd lines */
  204.         goto loop;
  205.  
  206.     /* Convert lower, and mixed case commands to UPPER case - Ashok */
  207.     for(cp = scb->buf;*cp != ' ' && *cp != '\0';cp++)
  208.         *cp = toupper(*cp);
  209.  
  210.     pop_sm(scb);
  211.     if (scb->state == DONE)
  212.         goto quit;
  213.  
  214.     goto loop;
  215.  
  216. quit:
  217.     log(scb->socket,"close POP3");
  218.     close_s(scb->socket);
  219.     delete_scb(scb);
  220. }
  221.  
  222.  
  223. /* Create control block, initialize */
  224.  
  225. static struct
  226. pop_scb *create_scb()
  227. {
  228.     register struct pop_scb *scb;
  229.  
  230.     if((scb = (struct pop_scb *)callocw(1,sizeof (struct pop_scb))) == NULLSCB)
  231.         return NULLSCB;
  232.  
  233.     scb->username[0] = '\0';
  234.     scb->msg = NULL;
  235.     scb->wf = NULL;
  236.  
  237.     scb->count = scb->folder_file_size = 0;
  238.  
  239.     scb->folder_modified = FALSE;
  240.     return scb;
  241. }
  242.  
  243.  
  244. /* Free msg link-list */
  245. static void
  246. delete_msglist(struct pop_msg *b_msg)
  247. {
  248.     struct pop_msg *msg,*msg2;
  249.     msg=b_msg;
  250.     while(msg!=NULL) {msg2=msg->next; free(msg); msg=msg2;}
  251. }
  252.  
  253. /* Free resources, delete control block */
  254.  
  255. static void
  256. delete_scb(scb)
  257. register struct pop_scb *scb;
  258. {
  259.     if (scb == NULLSCB)
  260.         return;
  261.     if (scb->wf != NULL)
  262.         fclose(scb->wf);
  263.     if (scb->msg  != NULL)
  264.         delete_msglist(scb->msg);
  265.  
  266.     free((char *)scb);
  267. }
  268.  
  269. /* replace terminating end of line marker(s) (\r and \n) with null,
  270.             and change . to .. */
  271. static void
  272. rrip(s)
  273. register char *s;
  274. {
  275.     register char *cp;
  276.  
  277.     if((cp = strchr(s,'\r')) != NULLCHAR)
  278.         *cp = '\0';
  279.     if((cp = strchr(s,'\n')) != NULLCHAR)
  280.         *cp = '\0';
  281. }
  282.  
  283. /* --------------------- start of POP server code ------------------------ */
  284.  
  285. #define BITS_PER_WORD   16
  286.  
  287. #define isSOM(x)        ((strncmp(x,"From ",5) == 0))
  288.  
  289. /* Command string specifications */
  290.  
  291. static char
  292.         user_cmd[] = "USER ",
  293.         pass_cmd[] = "PASS ",
  294.         quit_cmd[] = "QUIT",
  295.         stat_cmd[] = "STAT",
  296.         list_cmd[] = "LIST",
  297.         retr_cmd[] = "RETR",
  298.         dele_cmd[] = "DELE",
  299.         noop_cmd[] = "NOOP",
  300.         rset_cmd[] = "RSET",
  301.         top_cmd[]  = "TOP",
  302.         last_cmd[] = "LAST";
  303.  
  304. static void
  305. pop_sm(scb)
  306. struct pop_scb *scb;
  307. {
  308.     char password[40];
  309.  
  310. #ifndef __TURBOC__
  311.     static
  312. #endif
  313.     void state_error(struct pop_scb *,char *);
  314. #ifndef __TURBOC__
  315.     static
  316. #endif
  317.     void fatal_error(struct pop_scb *,char *);
  318. #ifndef __TURBOC__
  319.     static
  320. #endif
  321.     void open_folder(struct pop_scb *);
  322. #ifndef __TURBOC__
  323.     static
  324. #endif
  325.     void do_cleanup(struct pop_scb *);
  326. #ifndef __TURBOC__
  327.     static
  328. #endif
  329.     void stat_message(struct pop_scb *);
  330. #ifndef __TURBOC__
  331.     static
  332. #endif
  333.     void list_message(struct pop_scb *);
  334. #ifndef __TURBOC__
  335.     static
  336. #endif
  337.     void retr_message(struct pop_scb *);
  338. #ifndef __TURBOC__
  339.     static
  340. #endif
  341.     void dele_message(struct pop_scb *);
  342. #ifndef __TURBOC__
  343.     static
  344. #endif
  345.     void noop_message(struct pop_scb *);
  346. #ifndef __TURBOC__
  347.     static
  348. #endif
  349.     void last_message(struct pop_scb *);
  350. #ifndef __TURBOC__
  351.     static
  352. #endif
  353.     void rset_message(struct pop_scb *);
  354. #ifndef __TURBOC__
  355.     static
  356. #endif
  357.     void top_message(struct pop_scb *);
  358. #ifndef __TURBOC__
  359.     static
  360. #endif
  361.     void close_folder(struct pop_scb *);
  362.  
  363.     if (scb == NULLSCB) /* be certain it is good -- wa6smn */
  364.         return;
  365.  
  366.     switch(scb->state) {
  367.  
  368.     case AUTH:
  369.         if (strncmp(scb->buf,user_cmd,strlen(user_cmd)) == 0){
  370.             sscanf(scb->buf,"USER %s",scb->username);
  371.             (void) usprintf(scb->socket,user_rsp);
  372.  
  373.         } else if (strncmp(scb->buf,pass_cmd,strlen(pass_cmd)) == 0){
  374.             sscanf(scb->buf,"PASS %s",password);
  375.  
  376.             if (!poplogin(scb->username,password)) {
  377.                 log(scb->socket,"POP3 access DENIED to %s",
  378.                         scb->username);
  379.                 state_error(scb,"Access DENIED!!");
  380.                 return;
  381.             }
  382.  
  383.             log(scb->socket,"POP3 access granted to %s",
  384.                     scb->username);
  385.             open_folder(scb);
  386.         } else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0){
  387.             do_cleanup(scb);
  388.         } else
  389.             state_error(scb,"(AUTH) expected USER, PASS or QUIT");
  390.         break;
  391.  
  392.     case TRANS:
  393.         if (strncmp(scb->buf,stat_cmd,strlen(stat_cmd)) == 0)
  394.             stat_message(scb);
  395.  
  396.         else if (strncmp(scb->buf,list_cmd,strlen(list_cmd)) == 0)
  397.             list_message(scb);
  398.  
  399.         else if (strncmp(scb->buf,retr_cmd,strlen(retr_cmd)) == 0)
  400.             retr_message(scb);
  401.  
  402.         else if (strncmp(scb->buf,dele_cmd,strlen(dele_cmd)) == 0)
  403.             dele_message(scb);
  404.  
  405.         else if (strncmp(scb->buf,last_cmd,strlen(noop_cmd)) == 0)
  406.             noop_message(scb);
  407.  
  408.         else if (strncmp(scb->buf,last_cmd,strlen(last_cmd)) == 0)
  409.             last_message(scb);
  410.  
  411.         else if (strncmp(scb->buf,top_cmd,strlen(top_cmd)) == 0)
  412.             top_message(scb);
  413.  
  414.         else if (strncmp(scb->buf,rset_cmd,strlen(rset_cmd)) == 0)
  415.             rset_message(scb);
  416.  
  417.         else if (strncmp(scb->buf,quit_cmd,strlen(quit_cmd)) == 0)
  418.             do_cleanup(scb);
  419.  
  420.         else
  421.             state_error(scb,
  422.                     "(TRANS) unsupported/unrecognized command");
  423.         break;
  424.  
  425.     case DONE:
  426.         break;
  427.  
  428.     default:
  429.         fatal_error(scb,"(TOP) State Error!!");
  430.         break;
  431.     }
  432. }
  433.  
  434. static void
  435. #ifdef PROTOTYPES
  436. do_cleanup(struct pop_scb *scb)
  437. #else
  438. do_cleanup(scb)
  439. struct pop_scb *scb;
  440. #endif
  441. {
  442. #ifndef __TURBOC__
  443.     static
  444. #endif
  445.     void close_folder(struct pop_scb *);
  446.  
  447.     close_folder(scb);
  448.     (void) usprintf(scb->socket,signoff_msg);
  449.     scb->state = DONE;
  450. }
  451.  
  452. static void
  453. #ifdef PROTOTYPES
  454. state_error(struct pop_scb *scb,char *msg)
  455. #else
  456. state_error(scb,msg)
  457. struct pop_scb *scb;
  458. char *msg;
  459. #endif
  460. {
  461.     (void) usprintf(scb->socket,error_rsp,msg);
  462.     /* scb->state = DONE; */  /* Don't automatically hang up */
  463. }
  464.  
  465. static void
  466. #ifdef PROTOTYPES
  467. fatal_error(struct pop_scb *scb,char *msg)
  468. #else
  469. fatal_error(scb,msg)
  470. struct pop_scb *scb;
  471. char *msg;
  472. #endif
  473. {
  474.     (void) usprintf(scb->socket,error_rsp,msg);
  475.     scb->state = DONE;
  476. }
  477.  
  478. static void
  479. #ifdef PROTOTYPES
  480. close_folder(struct pop_scb *scb)
  481. #else
  482. close_folder(scb)
  483. struct pop_scb *scb;
  484. #endif
  485. {
  486.     char folder_pathname[64];
  487.     char line[TLINELEN];
  488.     FILE *fd;
  489.     int deleted = FALSE;
  490.     int msg_no = 0;
  491.     struct pop_msg *msg;
  492. #ifndef __TURBOC__
  493.     static
  494. #endif
  495.     int newmail(struct pop_scb *);
  496. #ifndef __TURBOC__
  497.     static
  498. #endif
  499.     void state_error(struct pop_scb *,char *);
  500. #ifndef __TURBOC__
  501.     static
  502. #endif
  503.     void fatal_error(struct pop_scb *,char *);
  504.  
  505.  
  506.     if (scb->wf == NULL)
  507.         return;
  508.  
  509.     if (!scb->folder_modified) {
  510.         /* no need to re-write the folder if we have not modified it */
  511.  
  512.         fclose(scb->wf);
  513.         scb->wf = NULL;
  514.  
  515.         delete_msglist(scb->msg);
  516.         scb->msg=NULL;
  517.         return;
  518.     }
  519.  
  520.  
  521.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  522.  
  523.     if (newmail(scb)) {
  524.         /* copy new mail into the work file and save the
  525.                     message count for later */
  526.  
  527.         if ((fd = fopen(folder_pathname,"r")) == NULL) {
  528.             fatal_error(scb,"Unable to add new mail to folder");
  529.             return;
  530.         }
  531.  
  532.         fseek(scb->wf,0,SEEK_END);
  533.         fseek(fd,scb->folder_file_size,SEEK_SET);
  534.         while (!feof(fd)) {
  535.             fgets(line,TLINELEN,fd);
  536.             fputs(line,scb->wf);
  537.         }
  538.  
  539.         fclose(fd);
  540.     }
  541.  
  542.     /* now create the updated mail folder */
  543.  
  544.     if ((fd = fopen(folder_pathname,"w")) == NULL){
  545.         fatal_error(scb,"Unable to update mail folder");
  546.         return;
  547.     }
  548.  
  549.     rewind(scb->wf);
  550.     msg=scb->msg;
  551.     while (!feof(scb->wf)){
  552.         fgets(line,TLINELEN,scb->wf);
  553.  
  554.         if (isSOM(line)){
  555.             if (msg!=NULL) msg=msg->next;
  556.             msg_no++;
  557.             if (msg!=NULL)
  558.                 deleted = msg->deleted;
  559.             else
  560.                 deleted = FALSE;
  561.         }
  562.  
  563.         if (deleted)
  564.             continue;
  565.  
  566.         fputs(line,fd);
  567.     }
  568.  
  569.     fclose(fd);
  570.     fclose(scb->wf);
  571.     scb->wf = NULL;
  572.     delete_msglist(scb->msg);
  573.     scb->msg=NULL;
  574.  
  575. }
  576.  
  577. static void
  578. #ifdef PROTOTYPES
  579. open_folder(struct pop_scb *scb)
  580. #else
  581. open_folder(scb)
  582. struct pop_scb *scb;
  583. #endif
  584. {
  585.     char folder_pathname[64];
  586.     char line[TLINELEN];
  587.     long pos;
  588.     FILE *fd;
  589.     FILE *tmpfile __ARGS((void));
  590.     struct stat folder_stat;
  591.     struct pop_msg *msg;
  592.  
  593.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  594.     scb->folder_len       = 0;
  595.     scb->folder_file_size = 0;
  596.     /* if (stat(folder_pathname,&folder_stat)){ */
  597.     if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  598.         (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  599.         scb->state  = TRANS;
  600.         return;         /* no file = OK */
  601.     }
  602.  
  603.     scb->folder_file_size = folder_stat.st_size;
  604.     if ((fd = fopen(folder_pathname,"r")) == NULL){
  605.         state_error(scb,"Unable to open mail folder");
  606.         return;
  607.     }
  608.  
  609.     if ((scb->wf = tmpfile()) == NULL) {
  610.         state_error(scb,"Unable to create work folder");
  611.         return;
  612.     }
  613.  
  614.     scb->msg=calloc(sizeof(struct pop_msg),1); /* create first element */
  615.     if (scb->msg==NULL)
  616.     {
  617.         fatal_error(scb,"Unable to create pointer list");
  618.         return;
  619.     }
  620.     scb->msg->next=NULL;
  621.     msg=scb->msg;
  622.     msg->len=0;
  623.     msg->deleted=0;
  624.  
  625.     while(!feof(fd)) {
  626.         pos=ftell(scb->wf);
  627.         fgets(line,TLINELEN,fd);
  628.  
  629.         /* scan for begining of a message */
  630.  
  631.         if (isSOM(line))
  632.         {
  633.             scb->folder_len++;
  634.             msg->next=calloc(sizeof(struct pop_msg),1);
  635.             if (msg->next==NULL)
  636.             {
  637.                 fatal_error(scb,
  638.                         "Unable to create pointer list");
  639.                 return;
  640.             }
  641.             msg=msg->next;
  642.             msg->pos=pos;
  643.             msg->next=NULL;
  644.             msg->len=0;
  645.             msg->deleted=0;
  646.  
  647.         /* now put  the line in the work file */
  648.         }
  649.         fputs(line,scb->wf);
  650.         rrip(line);
  651.         if ( *line == '.' ) msg->len++;
  652.         msg->len +=strlen(line)+2; /* Add msg len count */
  653.     }
  654.  
  655.     fclose(fd);
  656.     scb->high_num=0;  /* reset high read */
  657.  
  658.     (void) usprintf(scb->socket,count_rsp,scb->folder_len);
  659.  
  660.     scb->state  = TRANS;
  661. }
  662.  
  663. static void
  664. #ifdef PROTOTYPES
  665. stat_message(struct pop_scb *scb)
  666. #else
  667. stat_message(scb)
  668. struct pop_scb *scb;
  669. #endif
  670. {
  671.     long total=0;
  672.     int count=0;
  673.     struct pop_msg *msg;
  674.  
  675.     if (scb == NULLSCB) /* check for null -- wa6smn */
  676.         return;
  677.  
  678.     if (scb->folder_len)    /* add everything up */
  679.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  680.             if (!msg->deleted)
  681.                 {       total += msg->len; ++count;}
  682.  
  683.     (void) usprintf(scb->socket,stat_rsp,count,total);
  684. }
  685.  
  686. static void
  687. #ifdef PROTOTYPES
  688. list_message(struct pop_scb *scb)
  689. #else
  690. list_message(scb)
  691. struct pop_scb *scb;
  692. #endif
  693. {
  694.     struct pop_msg *msg;
  695.     int msg_no=0;
  696.     long total=0;
  697. #ifndef __TURBOC__
  698.     static
  699. #endif
  700.     struct pop_msg *goto_msg(struct pop_scb *,int );
  701.  
  702.     if (scb == NULLSCB) /* check for null -- wa6smn */
  703.         return;
  704.     if (scb->buf[sizeof(list_cmd) - 1] == ' ')
  705.     {
  706.         msg_no = atoi(&(scb->buf[sizeof(list_cmd) - 1]));
  707.         msg=goto_msg(scb,msg_no);
  708.         if (msg==NULL || msg->deleted)
  709.             state_error(scb,"non existent or deleted message");
  710.         else
  711.             (void) usprintf(scb->socket,list_single_rsp,
  712.             msg_no,msg->len);
  713.     } else  /* multiline */
  714.     {
  715.         if (scb->folder_len)            /* add everything */
  716.             for (msg=scb->msg->next; msg!=NULL;msg=msg->next)
  717.                 if (!msg->deleted)
  718.         total += msg->len,++msg_no;
  719.  
  720.         (void) usprintf(scb->socket,list_multi_rsp,
  721.                 msg_no,total);
  722.  
  723.         if (scb->folder_len)
  724.             for (msg=scb->msg->next,msg_no=1; msg!=NULL;
  725.                     msg=msg->next,msg_no++)
  726.                 if (!msg->deleted) {
  727.                     (void) usprintf(scb->socket,"%d %ld\n",
  728.                         msg_no,msg->len);
  729.                 }
  730.         (void) usprintf(scb->socket,multi_end_rsp);
  731.     }
  732. }
  733.  
  734. static void
  735. #ifdef PROTOTYPES
  736. retr_message(struct pop_scb *scb)
  737. #else
  738. retr_message(scb)
  739. struct pop_scb *scb;
  740. #endif
  741. {
  742.     char line[TLINELEN];
  743.     long cnt;
  744.     int msg_no;
  745.     struct pop_msg *msg;
  746. #ifndef __TURBOC__
  747.     static
  748. #endif
  749.     struct pop_msg *goto_msg(struct pop_scb *,int );
  750.  
  751.     if (scb == NULLSCB) /* check for null -- wa6smn */
  752.         return;
  753.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  754.     {
  755.         state_error(scb,"no such message");
  756.         return;
  757.     }
  758.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  759.     msg=goto_msg(scb,msg_no);
  760.     if (msg==NULL || msg->deleted) {
  761.         state_error(scb,"no such message");
  762.         return;
  763.     }
  764.  
  765.     cnt  = msg->len;
  766.     (void) usprintf(scb->socket,retr_rsp,cnt);
  767.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  768.  
  769.     while(!feof(scb->wf) && (cnt > 0)) {
  770.         fgets(line,TLINELEN,scb->wf);
  771.         rrip(line);
  772.         if ( *line == '.' ) {
  773.             (void) usprintf(scb->socket,".");
  774.             cnt--;
  775.         }
  776.         (void) usputs(scb->socket,line);
  777.         (void) usputc(scb->socket,'\n');
  778.         cnt -= (strlen(line)+2); /* Compensate for CRLF */
  779.     }
  780.     (void) usprintf(scb->socket,".\n");
  781.     if (msg_no >= scb->high_num)
  782.         scb->high_num=msg_no;     /* bump high water mark */
  783. }
  784.  
  785. static void
  786. #ifdef PROTOTYPES
  787. noop_message(struct pop_scb *scb)
  788. #else
  789. noop_message(scb)
  790. struct pop_scb *scb;
  791. #endif
  792. {
  793.         (void) usprintf(scb->socket,noop_rsp);
  794. }
  795.  
  796. static void
  797. #ifdef PROTOTYPES
  798. last_message(struct pop_scb *scb)
  799. #else
  800. last_message(scb)
  801. struct pop_scb *scb;
  802. #endif
  803. {
  804.     (void) usprintf(scb->socket,last_rsp,scb->high_num);
  805. }
  806.  
  807. static void
  808. #ifdef PROTOTYPES
  809. rset_message(struct pop_scb *scb)
  810. #else
  811. rset_message(scb)
  812. struct pop_scb *scb;
  813. #endif
  814. {
  815.     struct pop_msg *msg;
  816.     long total=0;
  817.  
  818.     if (scb->folder_len)
  819.         for (msg=scb->msg->next; msg!=NULL; msg=msg->next)
  820.             msg->deleted=FALSE,total+=msg->len;
  821.  
  822.     scb->high_num=0;  /* reset last */
  823.     scb->folder_modified=FALSE;
  824.     (void) usprintf(scb->socket,list_multi_rsp,scb->folder_len,total);
  825. }
  826.  
  827. static void
  828. #ifdef PROTOTYPES
  829. top_message(struct pop_scb *scb)
  830. #else
  831. top_message(scb)
  832. struct pop_scb *scb;
  833. #endif
  834. {
  835.     char *ptr;
  836.     char line[TLINELEN];
  837.     struct pop_msg *msg;
  838.     int msg_no=0,lines=0;
  839.     long total=0;
  840.  
  841. #ifndef __TURBOC__
  842.     static
  843. #endif
  844.     struct pop_msg *goto_msg(struct pop_scb *,int );
  845.  
  846.     if (scb == NULLSCB) /* check for null -- wa6smn */
  847.         return;
  848.     if (scb->buf[sizeof(top_cmd) - 1] != ' ')
  849.     {
  850.         state_error(scb,"No message specified");
  851.         return;
  852.     }
  853.     for (ptr=scb->buf+sizeof(top_cmd); *ptr==' ' ; ++ptr);
  854.         /* Space drop */
  855.     for ( ; *ptr!=' ' && *ptr !='\0'; ++ptr);
  856.         /* token drop */
  857.     msg_no = atoi(&(scb->buf[sizeof(top_cmd) - 1]));
  858.     lines = atoi(++ptr);  /* Get # lines to top */
  859.     if (lines < 0) lines=0;
  860.  
  861.     msg=goto_msg(scb,msg_no);
  862.     if (msg==NULL || msg->deleted)
  863.     {
  864.         state_error(scb,"non existent or deleted message");
  865.         return;
  866.     }
  867.     fseek(scb->wf,msg->pos,SEEK_SET);  /* Go there */
  868.     total=msg->len;  /* Length of current message */
  869.     (void) usprintf(scb->socket,noop_rsp);  /* Give OK */
  870.     do {
  871.         fgets(line,TLINELEN,scb->wf);
  872.         rrip(line);
  873.         if ( *line == '.' ) {
  874.             (void) usprintf(scb->socket,".");
  875.             total--;
  876.         }
  877.         total -= strlen(line)+2;
  878.         (void) usputs(scb->socket,line);
  879.         (void) usputc(scb->socket,'\n');
  880.     } while (*line!='\0' && total>0);
  881.     for ( ; total > 0 && lines; --lines) {
  882.         fgets(line,TLINELEN,scb->wf);
  883.         rrip(line);
  884.         if ( *line == '.' ) {
  885.             (void) usprintf(scb->socket,".");
  886.             total--;
  887.         }
  888.         total -= strlen(line)+2;
  889.         (void) usputs(scb->socket,line);
  890.         (void) usputc(scb->socket,'\n');
  891.     }
  892.     (void) usprintf(scb->socket,multi_end_rsp);
  893. }
  894.  
  895. static int
  896. poplogin(username,pass)
  897. char *pass;
  898. char *username;
  899. {
  900.     char buf[80];
  901.     char *cp;
  902.     char *cp1;
  903.     FILE *fp;
  904.  
  905.     if((fp = fopen(Popusers,"r")) == NULLFILE) {
  906.         /* User file doesn't exist */
  907.         tprintf("POP users file %s not found\n",Popusers);
  908.         return(FALSE);
  909.     }
  910.  
  911.     while(fgets(buf,sizeof(buf),fp),!feof(fp)) {
  912.         if(buf[0] == '#')
  913.             continue; /* Comment */
  914.  
  915.         if((cp = strchr(buf,':')) == NULLCHAR)
  916.             /* Bogus entry */
  917.             continue;
  918.  
  919.         *cp++ = '\0';  /* Now points to password */
  920.         if(strcmp(username,buf) == 0)
  921.             break;  /* Found user name */
  922.     }
  923.  
  924.     if(feof(fp)) {
  925.         /* User name not found in file */
  926.  
  927.         fclose(fp);
  928.         return(FALSE);
  929.     }
  930.     fclose(fp);
  931.  
  932.     if ((cp1 = strchr(cp,':')) == NULLCHAR)
  933.         return(FALSE);
  934.  
  935.     *cp1 = '\0';
  936.     if(strcmp(cp,pass) != 0) {
  937.         /* Password required, but wrong one given */
  938.  
  939.         return(FALSE);
  940.     }
  941.  
  942.     /* whew! finally made it!! */
  943.  
  944.     return(TRUE);
  945. }
  946.  
  947. static void
  948. #ifdef PROTOTYPES
  949. dele_message(struct pop_scb *scb)
  950. #else
  951. dele_message(scb)
  952. struct pop_scb *scb;
  953. #endif
  954. {
  955.     struct pop_msg *msg;
  956.     int msg_no;
  957. #ifndef __TURBOC__
  958.     static
  959. #endif
  960.     struct pop_msg *goto_msg(struct pop_scb *,int );
  961.  
  962.     if (scb == NULLSCB) /* check for null -- wa6smn */
  963.         return;
  964.     if (scb->buf[sizeof(retr_cmd) - 1] != ' ')
  965.     {
  966.         state_error(scb,"no such message");
  967.         return;
  968.     }
  969.     msg_no = atoi(&(scb->buf[sizeof(retr_cmd) - 1]));
  970.     msg=goto_msg(scb,msg_no);
  971.     if (msg==NULL || msg->deleted) {
  972.         state_error(scb,"attempt to access deleted message");
  973.         return;
  974.     }
  975.     if (msg->deleted) /* Don't bother if already dead */
  976.     {
  977.             state_error(scb,"message already deleted");
  978.             return;
  979.     }
  980.     msg->deleted=TRUE;
  981.     scb->folder_modified = TRUE;
  982.     (void) usprintf(scb->socket,dele_rsp,msg_no);
  983. }
  984.  
  985. static int
  986. #ifdef PROTOTYPES
  987. newmail(struct pop_scb *scb)
  988. #else
  989. newmail(scb)
  990. struct pop_scb *scb;
  991. #endif
  992. {
  993.     char folder_pathname[64];
  994.     struct stat folder_stat;
  995.  
  996.     sprintf(folder_pathname,"%s/%s.txt",Mailspool,scb->username);
  997.  
  998.     /* if (stat(folder_pathname,&folder_stat)) { */
  999.     if((folder_stat.st_size = fsize(folder_pathname)) == -1) { /* N1BEE */
  1000.         state_error(scb,"Unable to get old mail folder's status");
  1001.         return(FALSE);
  1002.     } else
  1003.         return ((folder_stat.st_size > scb->folder_file_size)? TRUE:FALSE);
  1004. }
  1005.  
  1006. static struct pop_msg *
  1007. goto_msg(struct pop_scb *scb,int msg_no)
  1008. {
  1009.     int msg_num;
  1010.     struct pop_msg *msg;
  1011.  
  1012.     msg_num=msg_no-1;
  1013.     if (scb->folder_len==0 || msg_num < 0)
  1014.             return NULL;
  1015.     for (msg=scb->msg->next; msg_num && msg!=NULL; --msg_num) msg=msg->next;
  1016.     return msg;
  1017. }
  1018.  
  1019. #endif
  1020.  
  1021.